package com.hsmpay.common.util.jiami;

import it.sauronsoftware.base64.Base64;
import org.apache.log4j.Logger;
import com.hsmpay.utils.MD5;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.Key;

/**
 * 3DES加密工具类
 *
 * @date 2014-04-17
 */
public class Des3 {
    static Logger log = Logger.getLogger(Des3.class);
    // 密钥
    private final static String secretKey = "zhongyi@163.com$#6688#$";
    // 向量
    private final static String iv = "87654321";
    // 加解密统一使用的编码方式
    private final static String encoding = "utf-8";

    /**
     * 3DES加密
     *
     * @param plainText 普通文本
     * @param secretKey
     * @return
     * @throws Exception
     */
    public static String encode(String plainText, String secretKey) {
        try {
            Key deskey = null;
            DESedeKeySpec spec = new DESedeKeySpec(secretKey.getBytes());
            SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
            deskey = keyfactory.generateSecret(spec);

            Cipher cipher = Cipher.getInstance("desede/CBC/PKCS5Padding");
            IvParameterSpec ips = new IvParameterSpec(iv.getBytes());
            cipher.init(Cipher.ENCRYPT_MODE, deskey, ips);
            byte[] encryptData = cipher.doFinal(plainText.getBytes(encoding));
            //return Des3Base64.encode(encryptData);
            byte[] bb = Base64.encode(encryptData);
            return new String(bb, "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return plainText;
    }

    /**
     * 3DES加密
     *
     * @param plainText 普通文本
     * @return
     * @throws Exception
     */
    public static String encode(String plainText) {
        return encode(plainText, secretKey);
    }

    /**
     * 3DES解密
     *
     * @param encryptText 加密文本
     * @return
     * @throws Exception
     */
    public static String decode(String encryptText, String secretKey) {
        try {
            Key deskey = null;
            DESedeKeySpec spec = new DESedeKeySpec(secretKey.getBytes());
            SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
            deskey = keyfactory.generateSecret(spec);
            Cipher cipher = Cipher.getInstance("desede/CBC/PKCS5Padding");
            IvParameterSpec ips = new IvParameterSpec(iv.getBytes());
            cipher.init(Cipher.DECRYPT_MODE, deskey, ips);

            //byte[] decryptData = cipher.doFinal(Des3Base64.decode(encryptText));
            byte[] decryptData = cipher.doFinal(Base64.decode(encryptText.getBytes("UTF-8")));
            return new String(decryptData, encoding);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return encryptText;
    }

    /**
     * 3DES解密
     *
     * @param encryptText 加密文本
     * @return
     * @throws Exception
     */
    public static String decode(String encryptText) {
        return decode(encryptText, secretKey);
    }

    /**
     * 生成8位DES密钥  转码的16位密钥
     *
     * @return
     */
    public static String generate16Key() {
        KeyGenerator kg;
        try {
            kg = KeyGenerator.getInstance("DES");
            kg.init(56);
            SecretKey secretKey = kg.generateKey();
            byte[] key = secretKey.getEncoded();
            return byte2hex(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 转换成十六进制字符串
     *
     * @param b
     * @return
     */
    public static String byte2hex(byte[] b) {
        String hs = "";
        String stmp = "";

        for (int n = 0; n < b.length; n++) {
            stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
            if (stmp.length() == 1)
                hs = hs + "0" + stmp;
            else
                hs = hs + stmp;
            //if (n<b.length-1)  hs=hs+":";
        }
        return hs.toUpperCase();
    }

    /**
     * 生成8位DES密钥  转码的32位密钥
     *
     * @return
     */
    public static String generate32Key() {
        return MD5.mD5ofStr(generate16Key());
    }

    public static byte[] hexStringToByte(String hex) {
        hex = hex.toUpperCase();
        int len = (hex.length() / 2);
        byte[] result = new byte[len];
        char[] achar = hex.toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
        }
        return result;
    }

    private static byte toByte(char c) {
        byte b = (byte) "0123456789ABCDEF".indexOf(c);
        return b;
    }


    /**
     * 3DES解密
     *
     * @param dataS 解密数据
     * @return keys 密钥
     */
    public static String decode3DES(String dataS, String keys) throws Exception {
        String result = "";
        try {
            byte[] data = hexStringToByte(dataS);
            byte[] key = hexStringToByte(keys);
            byte[] km = new byte[24];
            System.arraycopy(key, 0, km, 0, 16);
            System.arraycopy(key, 0, km, 16, 8);
            Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
            DESedeKeySpec dks = new DESedeKeySpec(km);
            SecretKey k = SecretKeyFactory.getInstance("DESede")
                    .generateSecret(dks);
            cipher.init(Cipher.DECRYPT_MODE, k);
            result = byte2hex(cipher.doFinal(data));
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception(e);
        }
        return result;
    }

    /**
     * 3DES加密
     *
     * @param key  密钥
     * @param data 待加密数据
     * @return byte[] 加密数据
     */
    public static byte[] encode3DES(byte[] key, byte[] data) throws Exception {
        try {
            byte[] km = new byte[24];
            System.arraycopy(key, 0, km, 0, 16);
            System.arraycopy(key, 0, km, 16, 8);
            Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
            DESedeKeySpec dks = new DESedeKeySpec(km);
            SecretKey k = SecretKeyFactory.getInstance("DESede")
                    .generateSecret(dks);
            cipher.init(Cipher.ENCRYPT_MODE, k);
            byte[] result = cipher.doFinal(data);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception(e);
        }
    }

    /**
     * 3DES加密
     *
     * @param dataS 待加密数据
     * @return keys 加密数据
     */
    public static String encode3DES(String dataS, String keys) throws Exception {
        byte[] data = hexStringToByte(dataS);
        byte[] key = hexStringToByte(keys);
        String result = byte2hex(encode3DES(key, data));
        return result;
    }

    /**
     * DES解密
     *
     * @param myinfo
     * @param key
     * @return
     */
    public static byte[] decodc(byte[] myinfo, byte[] key) throws Exception {
        String Algorithm = "DES"; //DES,DESede,Blowfish
        try {
            DESKeySpec dks = new DESKeySpec(key);

            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(Algorithm);
            SecretKey deskey = keyFactory.generateSecret(dks);

            //log.debug("解密前数据=[" + byte2hex(myinfo)+"]");

            Cipher c1 = Cipher.getInstance("DES/ECB/NoPadding");
            c1.init(Cipher.DECRYPT_MODE, deskey);

            byte[] cipherByte = c1.doFinal(myinfo);
            //log.debug("解密结果=[" + byte2hex(cipherByte)+"]");
            return cipherByte;

        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

    /**
     * DES加密
     *
     * @param myinfo
     * @param key
     * @return
     */
    public static byte[] encodc(byte[] myinfo, byte[] key) throws Exception {
        // Security.addProvider(new com.sun.crypto.provider.SunJCE());
        String Algorithm = "DES"; //DES,DESede,Blowfish
        try {
            DESKeySpec dks = new DESKeySpec(key);

            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(Algorithm);
            SecretKey deskey = keyFactory.generateSecret(dks);
            //log.debug("加密前数据=[" + byte2hex(myinfo)+"]");
            Cipher c1 = Cipher.getInstance("DES/ECB/NoPadding");
            //Cipher c1 = Cipher.getInstance("DES");
            c1.init(Cipher.ENCRYPT_MODE, deskey);
            byte[] cipherByte = c1.doFinal(myinfo);
            //log.debug("加密结果=[" + byte2hex(cipherByte)+"]");
            return cipherByte;

        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

    //异或
    public static byte[] XORContent(byte[] content1, byte[] content2) {
        int i = 0;
        int len = content1.length;
        //byte []sOutMAC =new byte[8];
        byte[] res = new byte[len];
        for (i = 0; i < len; i++) {
            res[i] = (byte) (content1[i] ^ content2[i]);
        }
        return res;

    }

    /**
     * 转成十六进制数字
     *
     * @param n
     * @return
     */
    public static String Int2HexStr(int n) {
        String HexStr = Integer.toHexString(n);
        HexStr = HexStr.length() == 1 ? "0" + HexStr : HexStr;
        return HexStr;
    }

    public static byte[] getDESKey(String hexKey) {
        String strKey = hexKey.toUpperCase();
        return hexStringToByte(strKey);
    }

    /**
     * PIN加密
     *
     * @param Pan    卡号
     * @param Pin    密码
     * @param PinKey 密码密钥
     * @return
     */
    public static String encryptPin(String Pan, String Pin, String PinKey) throws Exception {
        String DesPin = "";
        try {
            Pan = Pan.substring(Pan.length() - 13, Pan.length() - 1);
            int PanLen = Pan.length();
            for (int i = 0; i < 16 - PanLen; i++) {
                Pan = "0" + Pan;
            }
            Pin = Int2HexStr(Pin.length()) + Pin;
            int PinLen = Pin.length();
            for (int j = 0; j < 16 - PinLen; j++) {
                Pin += "F";
            }
            byte[] res = XORContent(hexStringToByte(Pin), hexStringToByte(Pan));
            log.debug("异或数据=[" + Pan + "][" + Pin + "]");
            log.debug("异或的结果=[" + byte2hex(res) + "]");
            if (PinKey.length() == 32) {
                log.debug("=====加密开始========");
                log.debug("加密数据=[" + byte2hex(res) + "][" + PinKey + "]");
                byte[] res1 = encode3DES(getDESKey(PinKey), res);
                DesPin = byte2hex(res1);
                log.debug("加密的结果=[" + DesPin + "]");
                log.debug("=====加密结束========");
            } else {
                log.debug("=====加密开始========");
                log.debug("加密数据=[" + byte2hex(res) + "][" + PinKey + "]");
                byte[] res1 = encodc(res, getDESKey(PinKey));
                DesPin = byte2hex(res1);
                log.debug("加密的结果=[" + DesPin + "]");
                log.debug("=====加密结束========");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
        return DesPin;
    }

    /**
     * 二磁道加密
     *
     * @param trkKey
     * @param track
     * @return
     */
    public static String encryptStanderTranck(String trkKey, String track) throws Exception {
        log.debug("trkKey:" + trkKey);
        int trkLen = track.length();
        //track=Int2HexStr(trkLen)+track;
        int mod = trkLen % 16;
        log.debug("mod:" + mod);
        for (int i = 0; i < 16 - mod; i++) {
            track += "F";
        }

        String mTrack = "";
        try {
            log.debug("track:" + track);
            mTrack = byte2hex(encode3DES(hexStringToByte(trkKey), hexStringToByte(track)));
            mTrack = Int2HexStr(trkLen) + mTrack;
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }

        return mTrack;
    }

    public static void main(String[] args) throws Exception {

//		String PinKey="E3D13ACC2EC98480039FE9F955961CC0";
//		String Pin="123456";
//		String Pan = "6226220286298871";
//		String desPin = encryptPin(Pan, Pin, PinKey);
//		log.debug("desPin = "+desPin);
//		

//		
//		String track2Data="6222021001086720528d49121209499991227";
//		String trkKey="FCEC16E3CC524B9D380FCCC34E40F502";
//		String deStrack2Data = encryptStanderTranck(trkKey,track2Data);
//		log.debug("deStrack2Data = "+deStrack2Data);
//		


    }

//	public static void main(String args[]){
//		String s1 = "明文数据";
//		System.out.println("明文数据:"+s1);
//		try {
//			String s2 = encode(s1);
//			System.out.println("密文数据:"+s2);
//			String s3 = decode(s2);
//			System.out.println("解密数据:"+s3);
//			
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//	}


}
